﻿/*
 * @Autor: PK
 * @Date: 2021-03-31 16:36:36
 * @Description: 车站：
 */

using System;
using System.Collections.Generic;
using System.Diagnostics;
using O2DESNet.Distributions;
using ShkSimulation.core.exceptions;
using ShkSimulation.carsharing;
using ShkSimulation.core.template.customer;
using ShkSimulation.core.util;
using ShkSimulation.carsharing.impl.model.dispatch;

namespace ShkSimulation.carsharing.impl.elements {

    public partial class Station: CarsharingStation, DispatchSupported{

        public PriorityQueue<Vehicle> Vehicles { get; private set; }
        public Queue<Dispatcher> Dispatchers { get; private set; } = new Queue<Dispatcher>();
        public PriorityQueue<Vehicle> VirtualSpaceVehicle{ get; private set; }
        
        protected DuplicateSortedList<DateTime, CarsharingTraveler> WaitServeList 
            = new DuplicateSortedList<DateTime, CarsharingTraveler>(DateTimeComparator.EarlyFirst);

        public DispatchHelper DispatchHelper { get; set; }

        /**
         * 还车的到达，只增加车辆数，HC_InQueue：空闲车数量，判断车多不多，调度
         */
        private void VehicleArrive(CarsharingVehicle vehicle) {
            Vehicle vehicleCome = vehicle as Vehicle;
            vehicleCome.StartChargeTime = ClockTime;
            double cost = vehicleCome.FuelCost * vehicleCome.Distance;
            TotalCost += cost;
            vehicleCome.TotalCost += cost;
            vehicleCome.UpdateBattery();
            vehicleCome.UntieCustomer();
            //系统中车数量大于容量,进入虚拟空间
            if (Vehicles.Count >= Capacity) {
                //进入虚拟空间
                VirtualSpaceCounter.ObserveChange(1, ClockTime);
                VirtualSpaceVehicle.Add(vehicleCome);
                vehicleCome.TimeArriveStation = ClockTime;
            } else {
                //进入停车位
                Vehicles.Add(vehicleCome);
                vehicleCome.TimeStopBilling = ClockTime;
                double income = vehicleCome.Price * (ClockTime - vehicleCome.TimeToArriveRoad).TotalHours + cost;
                vehicleCome.Income += income;
                Income += income;
            }
            //系统车辆总数和可用车辆增加
            StationVehicleCounter.ObserveChange(1, ClockTime);
            FreeStationVehicleCounter.ObserveChange(1, ClockTime);
        }

        public override void TravelerArrive(CarsharingTraveler traveler) {
            Debug.Assert(FreeVehicleCount == Vehicles.Count + VirtualSpaceVehicle.Count, "不相等啦");
            // 是调度员有车/不满足调度条件
            if (traveler is Dispatcher dispatcher) {
                if (traveler.Vehicle != null) {
                    //乘车到达，结束
                    dispatcher.EndDispatch(ClockTime);
                    VehicleArrive(traveler.Vehicle);
                }
                this.Dispatchers.Enqueue(dispatcher);
                DispatchHelper?.TryDispatch(this);
                return;
            }
            if (traveler.Vehicle != null) {
                VehicleArrive(traveler.Vehicle);
                DispatchHelper?.TryDispatch(this);
                return;
            }
            CountArrive(traveler);
            if (!VehicleAvailable(traveler)) {
                return;
            }
            Vehicle vehicle = GetFreeVehicle();
            vehicle.BindCustomer(traveler);
            if (ServingVehicleCounter.LastCount < ServerCount) {
                //有位置，取出一个进行服务
                InternalServe(traveler);
            } else {
                //进队列
                WaitServeList.Add(ClockTime, traveler);
                QueuingVehicleCounter.ObserveChange(1, ClockTime);
            }
        }
        
        public override void TravelerServe(CarsharingTraveler traveler) {
            CountServe(traveler);
            ServingVehicleCounter.ObserveChange(1, ClockTime);
            //服务开始离开车站的车
            traveler.Vehicle.TimeStartServe = ClockTime;
            //得到新的服务率
            TimeSpan hourlyServiceRate = ServiceRateHelper.GetAverageServiceTime();
            TimeSpan serviceTime = Exponential.Sample(DefaultRS, hourlyServiceRate);
            ServiceTimeCounter.ObserveCount(serviceTime.TotalHours, ClockTime);
            ServiceIntervalCounter.ObserveCount((ClockTime - ServiceIntervalCounter.LastTime).TotalHours, ClockTime);
            ScheduleDepart(traveler, serviceTime);
        }
        
        public override void TravelerDepart(CarsharingTraveler traveler) {
            ServingVehicleCounter.ObserveChange(-1, ClockTime);
            StationVehicleCounter.ObserveChange(-1, ClockTime);
            ServedCustomerCounter.ObserveChange(1, ClockTime);
            traveler.Vehicle.TimeLeaveStation = ClockTime;
            traveler.TimeLeaveStation = ClockTime;
            if (QueuingVehicleCounter.LastCount > 0 && QueuingVehicleCounter.LastCount < ServerCount) {
                QueuingVehicleCounter.ObserveChange(-1, ClockTime);
                TravelerServe(WaitServeList.RemoveFirstAndGetValue());
            }
            traveler.EnterNextAgency();
        }

        public Dispatcher GetDispatcher() {
            return Dispatchers.Dequeue();
        }
        
        public Vehicle PeekFreeVehicle() {
            if (FreeVehicleCount == 0) {
                return null;
            }
            while (VirtualSpaceVehicle.Count > 0 && Vehicles.Count < Capacity) {
                VirtualSpaceCounter.ObserveChange(-1, ClockTime);
                Vehicle vehicle = VirtualSpaceVehicle.RemoveFirstAndGetValue();
                vehicle.TimeStopBilling = ClockTime;
                double income = vehicle.Price * (ClockTime - vehicle.TimeToArriveRoad).TotalHours;
                vehicle.Income += income;
                Income += income;
                Vehicles.Add(vehicle);
            }
            Vehicle parkVehicle = Vehicles.GetFirst();
            return parkVehicle;
        }
        
        public Vehicle GetFreeVehicle() {
            if (FreeVehicleCount == 0) {
                throw new ErrorParamException("包租婆怎么没车啦");
            }
            while (VirtualSpaceVehicle.Count > 0 && Vehicles.Count < Capacity) {
                VirtualSpaceCounter.ObserveChange(-1, ClockTime);
                Vehicle vehicle = VirtualSpaceVehicle.RemoveFirstAndGetValue();
                vehicle.TimeStopBilling = ClockTime;
                double income = vehicle.Price * (ClockTime - vehicle.TimeToArriveRoad).TotalHours;
                vehicle.Income += income;
                Income += income;
                Vehicles.Add(vehicle);
            }
            FreeStationVehicleCounter.ObserveChange(-1, ClockTime);
            Vehicle parkVehicle = Vehicles.RemoveFirstAndGetValue();
            return parkVehicle;
        }

        public Vehicle GetDispatcherFreeVehicle() {
            Vehicle parkVehicle = GetFreeVehicle();
            StationVehicleCounter.ObserveChange(-1, ClockTime);
            return parkVehicle;
        }

        public DispatchInfo GetDispatcherInfo() {
            return DispatchInfo.Create(UniqueId, FreeVehicleCount, Dispatchers.Count);
        }

    }
}
